package asm.dispatch.test;

import org.ricks.asm.*;
import org.ricks.common.Tuple;
import org.ricks.ioc.AppContext;

import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

import static org.ricks.asm.Opcodes.*;

/**
 * @author chenwei
 * @Title:
 * @Package
 * @Description:
 * @date 2022/11/2915:34
 */
public class DispatchClassVisitor extends ClassVisitor {

    private static final List<Tuple> tupleList = DispatchManager.initPairs(AppContext.getApplication());
    public DispatchClassVisitor(ClassVisitor cv) {
        super(ASM7, cv);
    }

    @Override
    public final void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
//        cv.visitNestMember("org/demon/dispatch/Dispatcher$SingleCase");
//        cv.visitInnerClass("org/demon/dispatch/Dispatcher$SingleCase", "org/demon/dispatch/Dispatcher", "SingleCase", ACC_PRIVATE | ACC_STATIC);
//        cv.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC | ACC_FINAL | ACC_STATIC);


//        MethodVisitor methodVisitor = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "get", "()Lorg/demon/dispatch/Dispatcher;", null, null);
//`        methodVisitor.visitCode();
//        Label label0 = new Label();
//        methodVisitor.visitLabel(label0);
//        methodVisitor.visitLineNumber(23, label0);
//        methodVisitor.visitFieldInsn(GETSTATIC, "org/demon/dispatch/Dispatcher$SingleCase", "INSTANCE", "Lorg/demon/dispatch/Dispatcher;");
//        methodVisitor.visitInsn(ARETURN);
//        methodVisitor.visitMaxs(1, 0);
//        methodVisitor.visitEnd();`
        super.visit(version,access,name,signature,superName,interfaces);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions);
        System.err.println("访问方法的名称：" + name);
        if("dispatcher".equals(name.trim())) return new DispatchMethodVisitor(methodVisitor);
        return methodVisitor;
    }

    @Override
    public void visitEnd() {
        Set<String> classNames =  tupleList.stream().map(tuple -> (String)tuple.get(1)).collect(Collectors.toSet()); //对象入口
        initFieldVisitor(classNames, (ClassWriter) cv);
        MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
        mv.visitCode();
            int line = 19;
            for (String className : classNames) {
                String objName = className.substring(className.lastIndexOf(".") + 1,className.length()).toLowerCase(Locale.ROOT);
                String cName = className.replace(".","/");
                Label label0 = new Label();
                mv.visitLabel(label0);
                mv.visitLineNumber(line, label0);
                mv.visitLdcInsn(Type.getType("L"+cName+";"));
                mv.visitMethodInsn(INVOKESTATIC, "org/ricks/ioc/ApplicationContext", "getBean", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
                mv.visitTypeInsn(CHECKCAST, cName);
                mv.visitFieldInsn(PUTSTATIC, "org/ricks/dispatch/Dispatcher", objName, "L"+cName+";");
                line += 1;
            }
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 0);
        mv.visitEnd();
        super.visitEnd();
    }

    private static FieldVisitor initFieldVisitor(Set<String> classNames, ClassWriter classWriter) {
        FieldVisitor fieldVisitor = null;
        for (String className : classNames) {
            String objName = className.substring(className.lastIndexOf(".") + 1,className.length()).toLowerCase(Locale.ROOT);
            String cName = className.replace(".","/");
            fieldVisitor = classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, objName, "L"+cName+";", null, null);
            fieldVisitor.visitEnd();
        }
        return fieldVisitor;
    }
}
